using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace Pixysoft.Collections
{
    public class MostRecentlyUsedDictionary<T>
    {
        uint m_max = 50;
        DoubleLinkedList<T> m_list = new DoubleLinkedList<T>();
        Dictionary<string, DoubleLinkedList<T>.LinkItem> dictionary = new Dictionary<string, DoubleLinkedList<T>.LinkItem>();

        /// <summary>
        /// Default constructor for the most recently used items using the default size (50)
        /// </summary>
        public MostRecentlyUsedDictionary()
        {
            //
            // TODO: Add constructor logic here
            //
        }


        /// <summary>
        /// Construct a most recently used items list with the maximum number of items
        /// allowed in the list.
        /// </summary>
        /// <param name="maxItems">Maximum number of items allowed</param>
        public MostRecentlyUsedDictionary(uint maxItems)
        {
            m_max = maxItems;
        }

        public T this[string key]
        {
            get
            {

                DoubleLinkedList<T>.LinkItem item = (DoubleLinkedList<T>.LinkItem)dictionary[key];

                if (item == null)
                    return default(T);

                m_list.MoveToHead(item);

                return (item.Item);
            }
            set
            {
                DoubleLinkedList<T>.LinkItem link = null;

                if (dictionary.ContainsKey(key))
                {
                    link = (DoubleLinkedList<T>.LinkItem)dictionary[key];
                    link.Item = value;

                    m_list.MoveToHead(link);

                    dictionary[key] = link;
                }
                else
                {
                    Add(key, value);
                }
            }
        }

        public ICollection<string> Keys
        {
            get
            {
                return (dictionary.Keys);
            }
        }

        public void Add(string key, T value)
        {
            DoubleLinkedList<T>.LinkItem link = m_list.Prepend(key, value);

            dictionary.Add(key, link);

            OnInsert(key, value);
        }

        public bool Contains(string key)
        {
            bool hasKey = dictionary.ContainsKey(key);

            // Update the reference for this link
            if (hasKey)
                m_list.MoveToHead((DoubleLinkedList<T>.LinkItem)dictionary[key]);

            return (hasKey);
        }

        public void Remove(string key)
        {
            DoubleLinkedList<T>.LinkItem link =
                (DoubleLinkedList<T>.LinkItem)dictionary[key];

            dictionary.Remove(key);

            if (link != null)
            {
                m_list.RemoveLink(link);
            }
        }

        private void OnInsert(string key, T value)
        {
            while (dictionary.Keys.Count > m_max)
            {
                // Purge an item from the cache
                DoubleLinkedList<T>.LinkItem tail = m_list.TailLink;

                if (tail != null)
                {
                    m_list.RemoveLink(tail);

                    dictionary.Remove(tail.Key);
                }
            }
        }

        /// <summary>
        /// The maximum capacity of the list
        /// </summary>
        public uint Capacity
        {
            get { return m_max; }
            set
            {
                if (Capacity < 1)
                    throw new Exception("Negative number!");
                m_max = value;
            }
        }

        public override string ToString()
        {
            StringBuilder buff = new StringBuilder(Convert.ToInt32(m_max));

            buff.Append("[");

            foreach (object item in m_list)
            {
                if (buff.Length > 1)
                    buff.Append(", ");

                buff.Append(item.ToString());
            }

            buff.Append("]");

            return buff.ToString();
        }

    }
}
